#include "types.h"

bool Is_inCell( Cell& cell, Molecule& mol ) {
    if ( mol.pos.x > cell.left_border.x && mol.pos.x <= cell.right_border.x) {
        if ( mol.pos.y > cell.left_border.y && mol.pos.y <= cell.right_border.y ) {
            if ( mol.pos.z > cell.left_border.z && mol.pos.z <= cell.right_border.z ) {
                return true;
            }
        }
    }
    return false;
}

Split_area Create_split_area(Area_size area, Molecules_vector& mol_vector) {
    //
    // TODO
    // double split_range = Get_optimal_split_range( ??? );
    //
    double split_range = 2; 
    Split_area split_area( area, split_range );

    std::vector< Molecules_vector > cells_buff( split_area.cells.size() );

    for ( int i = 0; i < mol_vector.size(); ++i ) {
        for ( int j = 0; j < cells_buff.size() ; ++j  ) {
            if ( Is_inCell( split_area.cells[j] , mol_vector[i] ) ) {
                cells_buff[j].push_back( mol_vector[i] );
                break;
            }
        }
    }

    int last_index = 0;
    for ( int i = 0; i < split_area.cells.size(); ++i ) {
        split_area.cells[i].begin = split_area.mol_vector.size();
        std::move( cells_buff[i].begin(), cells_buff[i].end(), split_area.mol_vector.end() );
        split_area.cells[i].end = split_area.mol_vector.size();
    }
}

Split_area::Split_area( Area_size area, double split_range ) {
    
    if (! ( area.x >= split_range && area.y >= split_range && area.z >= split_range ) ) {
        throw std::invalid_argument{ "split_range must be less or equal to area size" };
    }

    vec3d left_border = { 0 , 0 , 0 };
    vec3d right_border = { 0 , 0 , 0 };

    uint num_x = (int)( area.x / split_range );
    uint num_y = (int)( area.y / split_range );
    uint num_z = (int)( area.z / split_range );

    std::vector<double> borders_x( num_x );
    std::vector<double> borders_y( num_y );
    std::vector<double> borders_z( num_z );
    
    for ( auto i = ++borders_x.begin(); i != borders_x.end(); i++) {
        *i = *( std::prev(i) ) + split_range; 
    }
    for ( auto i = ++borders_y.begin(); i != borders_y.end(); i++) {
        *i = *( std::prev(i) ) + split_range; 
    }
    for ( auto i = ++borders_z.begin(); i != borders_z.end(); i++) {
        *i = *( std::prev(i) ) + split_range; 
    }

    borders_x.push_back( area.x );
    borders_y.push_back( area.y );
    borders_z.push_back( area.z );
    

    cells.resize(num_x * num_y * num_z);
    auto curr_cell = cells.begin();

    for ( int k = 0; k < num_z; ++k ) {
        for ( int j = 0; j < num_y; ++j ) {
            for ( int i = 0; i < num_x; ++i ) {
                curr_cell->left_border.x = borders_x[i];
                curr_cell->left_border.y = borders_y[j];
                curr_cell->left_border.z = borders_z[k];

                curr_cell->right_border.x = borders_x[i + 1];
                curr_cell->right_border.y = borders_y[j + 1];
                curr_cell->right_border.z = borders_z[k + 1];

                curr_cell++;
            }
        }
    }
}

